/*
 * Copyright (C) 2014 Miquel Sas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package traderlib.core.data.types;

/**
 * A type that is the normal OHLC (open, high, low, close) values of a trading bar.
 *
 * @author Miquel Sas
 */
public class OHLC implements Comparable<Object> {

	/**
	 * Open.
	 */
	private double open = 0;
	/**
	 * High.
	 */
	private double high = 0;
	/**
	 * Low.
	 */
	private double low = 0;
	/**
	 * Close.
	 */
	private double close = 0;
	/**
	 * Volume.
	 */
	private double volume = 0;
	/**
	 * Open interest, normally not used.
	 */
	private double openInterest = 0;
	/**
	 * The time stamp when the bar has started to exist.
	 */
	private Timestamp timestamp = null;

	/**
	 * Default constructor.
	 */
	public OHLC() {
		super();
	}

	/**
	 * Get the open value.
	 *
	 * @return The open value.
	 */
	public double getOpen() {
		return open;
	}

	/**
	 * Set the open value.
	 *
	 * @param open The open value.
	 */
	public void setOpen(double open) {
		this.open = open;
	}

	/**
	 * Get the high value.
	 *
	 * @return The high value.
	 */
	public double getHigh() {
		return high;
	}

	/**
	 * Set the high value.
	 *
	 * @param high The high value.
	 */
	public void setHigh(double high) {
		this.high = high;
	}

	/**
	 * Get the low value.
	 *
	 * @return The low value.
	 */
	public double getLow() {
		return low;
	}

	/**
	 * Set the low value.
	 *
	 * @param low The low value.
	 */
	public void setLow(double low) {
		this.low = low;
	}

	/**
	 * Get the close value.
	 *
	 * @return The close value.
	 */
	public double getClose() {
		return close;
	}

	/**
	 * Set the close value.
	 *
	 * @param close The close value.
	 */
	public void setClose(double close) {
		this.close = close;
	}

	/**
	 * Get the volume.
	 *
	 * @return The volume.
	 */
	public double getVolume() {
		return volume;
	}

	/**
	 * Set the volume.
	 *
	 * @param volume The volume.
	 */
	public void setVolume(double volume) {
		this.volume = volume;
	}

	/**
	 * Get the open interest.
	 *
	 * @return The open interest.
	 */
	public double getOpenInterest() {
		return openInterest;
	}

	/**
	 * Set the open interest.
	 *
	 * @param openInterest The open interest.
	 */
	public void setOpenInterest(double openInterest) {
		this.openInterest = openInterest;
	}

	/**
	 * Get the timestamp when the bar was started.
	 *
	 * @return The timestamp.
	 */
	public Timestamp getTimestamp() {
		return timestamp;
	}

	/**
	 * Set the timestamp when the bar was started.
	 *
	 * @param timestamp The timestanmp.
	 */
	public void setTimestamp(Timestamp timestamp) {
		this.timestamp = timestamp;
	}

	/**
	 * Indicates whether some other object is "equal to" this one.
	 *
	 * @return A boolean.
	 * @param o The object to compare with.
	 */
	@Override
	public boolean equals(Object o) {
		if (o == null) {
			return false;
		}
		if (getClass() != o.getClass()) {
			return false;
		}
		final OHLC ohlc = (OHLC) o;
		if (getOpen() != ohlc.getOpen()) {
			return false;
		}
		if (getHigh() != ohlc.getHigh()) {
			return false;
		}
		if (getLow() != ohlc.getLow()) {
			return false;
		}
		if (getClose() != ohlc.getClose()) {
			return false;
		}
		if (getVolume() != ohlc.getVolume()) {
			return false;
		}
		if (getOpenInterest() != ohlc.getOpenInterest()) {
			return false;
		}
		if (getTimestamp() != null && ohlc.getTimestamp() == null) {
			return false;
		}
		if (getTimestamp() == null && ohlc.getTimestamp() != null) {
			return false;
		}
		return getTimestamp().equals(ohlc.getTimestamp());
	}

	/**
	 * Returns the hash code value for this ArrayList.
	 *
	 * @return The hash code
	 */
	@Override
	public int hashCode() {
		int hash = 0;
		hash ^= Double.valueOf(getOpen()).hashCode();
		hash ^= Double.valueOf(getHigh()).hashCode();
		hash ^= Double.valueOf(getLow()).hashCode();
		hash ^= Double.valueOf(getClose()).hashCode();
		hash ^= Double.valueOf(getVolume()).hashCode();
		hash ^= Double.valueOf(getOpenInterest()).hashCode();
		if (getTimestamp() != null) {
			hash ^= getTimestamp().hashCode();
		}
		return hash;
	}

	@Override
	public String toString() {
		StringBuilder b = new StringBuilder();
		b.append("Open: ");
		b.append(Double.toString(getOpen()));
		b.append("\n");
		b.append("High: ");
		b.append(Double.toString(getHigh()));
		b.append("\n");
		b.append("Low: ");
		b.append(Double.toString(getLow()));
		b.append("\n");
		b.append("Close: ");
		b.append(Double.toString(getClose()));
		b.append("\n");
		b.append("Volume: ");
		b.append(Double.toString(getVolume()));
		b.append("\n");
		if (getOpenInterest() != 0) {
			b.append("Open interest: ");
			b.append(Double.toString(getOpenInterest()));
			b.append("\n");
		}
		b.append("Timestamp: ");
		b.append(getTimestamp());
		return super.toString();
	}

	/**
	 * Returns a negative integer, zero, or a positive integer as this value is less than, equal to, or greater than the
	 * specified value. An OHLC object is compared first by the timestamp and secong by the range.
	 *
	 *
	 * @param o The value to compare.
	 * @return The compartion integer.
	 */
	@Override
	@SuppressWarnings("unchecked")
	public int compareTo(Object o) {
		OHLC ohlc = null;
		try {
			ohlc = (OHLC) o;
		} catch (ClassCastException exc) {
			throw new UnsupportedOperationException("Not comparable type: " + o.getClass().getName());
		}
		int compare = getTimestamp().compareTo(ohlc.getTimestamp());
		if (compare != 0) {
			return compare;
		}
		Double range_this = Double.valueOf(getRange());
		Double range_compare = Double.valueOf(ohlc.getRange());
		return range_this.compareTo(range_compare);
	}

	/**
	 * Returns the total range of the bar.
	 *
	 * @return The range.
	 */
	public double getRange() {
		return getHigh() - getLow();
	}
}
